home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
dbdoc.zip
/
MDXDOC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-06
|
14KB
|
362 lines
/* Somerset Data Systems, Inc. (908) 766-5845 */
/* Version 1.3 March 5, 1992 */
/* Programmer: Jay Parsons */
/****************************************************************************/
/* mdxdoc.c */
/* */
/* Program to analyze contents of an .mdx file. */
/* */
/****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mem.h>
/****************************************************************************/
/* definitions */
/****************************************************************************/
/**** **** values **** ****/
#define FALSE 0
#define TRUE 1
#define MDXTYPE 2 /* type code for .mdx file */
#define PRODTYPE 1 /* type code for production .mdx */
#define MAINHEADLEN 48 /* sizeof main header */
#define PAGELEN 512 /* length in bytes of a page */
#define TAGARRAYPAGE 1 /* offset of tag array in file in pages */
#define DESCRIPLEN 32 /* sizeof tag array descriptor */
#define INDHEADLEN 129 /* sizeof index header actually used */
#define CHARACTER 'C' /* character-type key expression */
#define DATE 'D' /* date-type key expression */
#define NUMERIC 'N' /* numeric-type key expression */
#define DESCENDING 0x08 /* index is descending */
#define TAGFIELD 0x10 /* shows tag is a field in file */
#define UNIQUE 0x40 /* index excludes duplicate keys */
#define SQLTYPE 1 /* optimized for SQL use */
#define BLOCKHEADLEN 8 /* header length of index body block */
/**** **** data types **** ****/
typedef unsigned long ulong; /* just an abbreviation */
/* dBASE date marker in file */
typedef struct
{
char year;
char month;
char day;
} dbfdate;
/* first 48 bytes of an .mdx file */
typedef struct
{
char filetype; /* error if not MDXTYPE */
dbfdate lastreindex; /* last reindex date */
char dbfname[16]; /* root name of associated .dbf */
int blocksize; /* SET BLOCKSIZE value, minimum = 2 */
int blockbytes; /* block size in bytes */
char production; /* 1 if production .mdx, else 0 */
char resrvd1[3];
int indexes; /* number of indexes in the file */
char resrvd2[2];
ulong endfilepage; /* page number of end of file */
ulong nextfreepage; /* page number of next free block */
ulong freepages; /* pages in next free block */
dbfdate created; /* file creation date */
char resrvd3[1];
} mdxheader;
/* descriptor of a tag */
typedef struct
{
long indheaderpage; /* page number of index header */
char tagname[11]; /* the tag name, in caps, null-filled */
char tagfieldflag; /* 10 if tag is a field, else 0 */
unsigned char counters[3]; /* mysterious usage counters */
unsigned char useless; /* always 02 */
unsigned char keytype; /* C, D, or N for key type */
char rsrvd[12];
} descriptor;
/* header of an index */
typedef struct
{
ulong rootpage; /* page number of index root */
ulong pagesused; /* pages used by the index */
int : 3;
int desc : 1; /* 1 if DESCENDING, or 0 */
int fieldtag : 1; /* 1 if tag is a field, or 0 */
int : 1;
int uniq : 1; /* 1 if index is UNIQUE, or 0 */
int : 1;
unsigned char keytype; /* C, D or N for key type */
unsigned char sql; /* 1 if optimized for SQL, or 0 */
char resrvd3;
unsigned keylength; /* length of key in bytes */
ulong maxnodes; /* maximum nodes in a block */
unsigned ireclen; /* length of an index record in bytes */
unsigned changes; /* change counter for optimization */
char resrvd4;
char uniqueflag; /* 40h if UNIQUE, or 0 */
char keyexpression[101]; /* the key expression itself */
} indexheader;
/* an index node */
typedef struct
{
ulong nodepointer; /* record number of this key value in */
/* .dbf if the node is in a block of */
/* nodes of the lowest level. Other- */
/* wise, page number of block of next */
/* lower level to search. */
char key[]; /* the key value, filled with garbage */
/* to a number of bytes divisible by 4 */
} node;
/* an index block */
typedef struct
{
ulong nodesinblock; /* nodes in use in this block of index */
ulong prevpage; /* page of logically previous block */
/* will be 0 if this block is first at */
/* this level */
node nodes[]; /* array of nodes */
ulong lowflag; /* 0 if this block is lowest level, or */
/* same as prevpage */
char garbage[]; /* to fill the block */
} indexblock;
/* globals */
extern char message[], tempbuff[], file_name[];
/**** **** function prototypes **** ****/
int mdxdoc ( char *filespec );
FILE *mdxopen ( char *filespec, mdxheader *buf );
/****************************************************************************/
/* mdxdoc */
/* Principal routine of this module. Reads and prints a description of */
/* the .mdx file identified by the filespec passed. */
/* Parameters: */
/* char *filespec -- pointer to specification of the .mdx file */
/* Returns: */
/* 0 if successful, 1 if any error occurs. */
/* Side effects: */
/* stores message, calls Printit. */
/* */
/****************************************************************************/
int mdxdoc ( char *filespec )
{
FILE *mdxfile;
mdxheader mainhead;
descriptor tag;
indexheader indexhead;
char tagtype[11];
int i, nexttag;
/* open file, check for .mdx type, print names */
if ( ( mdxfile = mdxopen( filespec, &mainhead ) ) == NULL )
{
sprintf( message, "Can't open file %s ", filespec );
return 1;
}
sprintf( message, "\n%s indexes the file %s ", filespec, mainhead.dbfname );
/* print production or not from byte 24 */
if ( mainhead.production == PRODTYPE )
strcat( message, "as its " );
else
strcat( message, "as a non-");
strcat( message, "production .mdx file.\n" );
printit( 0 );
/* print dates from bytes 02-04 and 45-47 */
sprintf( message, "It was originally created %02d/%02d/%02d",
(int) mainhead.created.month,
(int) mainhead.created.day,
(int) mainhead.created.year );
if ( mainhead.created.year == mainhead.lastreindex.year &&
mainhead.created.month == mainhead.lastreindex.month &&
mainhead.created.day == mainhead.lastreindex.day )
strcat( message, " and has not been reindexed since that date." );
else
sprintf( tempbuff, " and last reindexed %02d/%02d/%02d.",
(int) mainhead.lastreindex.month,
(int) mainhead.lastreindex.day,
(int) mainhead.lastreindex.year );
strcat( message, tempbuff );
printit( 0 );
/* print size and indexes from bytes 21-24 and 27-28 */
sprintf( message, "Its blocks are BLOCKSIZE %d, %d bytes long.\n",
mainhead.blocksize, mainhead.blockbytes );
printit( 0 );
sprintf( message, "It contains %d index", mainhead.indexes );
if ( mainhead.indexes > 1 )
strcat( message, "es" );
strcat( message, ":\n" );
printit( 0 );
/* point to first tag descriptor and loop through all */
nexttag = TAGARRAYPAGE * PAGELEN + DESCRIPLEN;
for ( i = 1; i <= mainhead.indexes; i++, nexttag += DESCRIPLEN )
{
/* read and print descriptor information */
if ( fseek( mdxfile, nexttag, SEEK_SET ) != 0 )
{
fclose( mdxfile );
strcpy( message, "Can't reach tag descriptor" );
return 1;
}
if ( fread( &tag, DESCRIPLEN, 1, mdxfile ) != 1 )
{
fclose( mdxfile );
strcpy( message, "Can't read tag descriptor" );
return 1;
}
if ( tag.tagfieldflag == TAGFIELD )
{
sprintf( message, "%-10s tags a ", tag.tagname );
strcpy( tagtype, "field" );
}
else
{
sprintf( message, "%-10s tags an ", tag.tagname );
strcpy( tagtype, "expression" );
}
sprintf( tempbuff, "%s of type %c", tagtype, tag.keytype );
strcat( message, tempbuff );
printit( 0 );
/* and index header information */
if ( fseek( mdxfile, tag.indheaderpage * PAGELEN, SEEK_SET ) != 0 )
{
fclose( mdxfile );
strcpy( message, "Can't reach index header" );
return 1;
}
if ( fread( &indexhead, INDHEADLEN, 1, mdxfile ) != 1 )
{
fclose( mdxfile );
strcpy( message, "Can't read index header" );
return 1;
}
if ( indexhead.uniq || indexhead.desc || indexhead.sql )
{
strcpy( message, "The index is " );
if ( indexhead.uniq )
{
strcat( message, "UNIQUE" );
if ( indexhead.desc && indexhead.sql )
strcat( message, ", DESCENDING and SQL-optimized" );
else
{
if( indexhead.desc )
strcat( message, " and DESCENDING" );
if( indexhead.sql )
strcat( message, " and SQL-optimized" );
}
}
else
if ( indexhead.desc && indexhead.sql )
strcat( message, "DESCENDING and SQL-optimized" );
else
if( indexhead.desc )
strcat( message, "DESCENDING" );
else
strcat( message, "SQL-optimized" );
strcat( message, "." );
printit( 0 );
}
sprintf( message, " Keys are %d byte", indexhead.keylength );
if( indexhead.keylength > 1 )
strcat( message, "s" );
sprintf( tempbuff, " long and the key %s is: %s",
tagtype, indexhead.keyexpression );
strcat( message, tempbuff );
printit( 0 );
}
fclose( mdxfile );
return 0;
}
/****************************************************************************/
/* mdxopen */
/* Routine to open .mdx file. */
/* Parameters: */
/* char *filespec -- pointer to spec of file to open */
/* mdxheader *buf -- pointer to mdxheader structure */
/* Returns: */
/* Pointer to C file control structure (to NULL if error) */
/* Side effects: */
/* Opens file and moves pointer to byte 48; fills buffer at buf with */
/* first 48 bytes of file. Closes file on error. */
/****************************************************************************/
FILE *mdxopen( char *filespec, mdxheader *buf )
{
FILE *file;
if ( ( file = fopen( filespec, "rb" ) ) == NULL )
{
sprintf( message, "Can't open file %s", filespec );
return NULL;
}
/* read the first 48 bytes into buffer */
if ( fread( buf, MAINHEADLEN, 1, file ) != 1 )
{
fclose( file );
strcpy( message, "Can't read .MDX header bytes" );
return NULL;
}
/* check first byte to be sure .mdx type */
if ( buf->filetype != MDXTYPE )
{
fclose( file );
strcpy( message, "Not a valid .MDX file" );
return NULL;
}
return file;
}